package org.myspringframework.core;

import org.dom4j.*;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class ClassPathXmlApplication implements ApplicationContext{

    private Map<String,Object> singletonObeject=new HashMap<>();
    private static final Logger logger= LoggerFactory.getLogger(ClassPathXmlApplication.class);

//解析myspring的配置文件，然后初始化所有的bean对象
    public ClassPathXmlApplication(String configLocation) {

        try {
            //解析myspring.xml文件，然后实例化Bean，将Bean存放到singletonObjects集合中。
            //这是dom4j的解析xml文件的核心对象。
            SAXReader reader = new SAXReader();
            //获取一个流，指向配置文件
            InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);
            Document dom = reader.read(in);
            //获取所有的bean标签
            List<Node> nodes = dom.selectNodes("//bean");
            nodes.forEach(node ->{

                try {
                    //向下转型的目的是为了使用Element接口里更丰富的方法。
                    Element beanElt = (Element) node;
                    //获取id属性
                    String id = beanElt.attributeValue("id");
                    String className = beanElt.attributeValue("class");

                    logger.info("beanName=" + id);
                    logger.info("beanClass=" + className);
                    //通过反射机制创建对象，将其放到Map集合中，提前曝光。
                    //获取Class
                    Class<?> aClass = Class.forName(className);
                    //获取无参数构造方法
                    Constructor<?> constructor = aClass.getDeclaredConstructor();
                    //调用无参数构造方法实例化bean
                    Object bean = constructor.newInstance();
                    //将bean“曝光”
                    singletonObeject.put(id,bean);
                    logger.info(singletonObeject.toString());
                }catch(Exception e){
                    e.printStackTrace();
                }
            });
            //再次重新把所有的bean标签遍历一次，这一次主要是给对象属性赋值
            nodes.forEach(node -> {
                try {
                    Element beanElt = (Element) node;
                    //获取id
                    String id = beanElt.attributeValue("id");
                    //获取className
                    String className = beanElt.attributeValue("class");
                    //获取class
                    Class<?> aClass = Class.forName(className);
                    Constructor<?> constructor = aClass.getDeclaredConstructor();
                    Object bean = constructor.newInstance();

                    //获取该bean标签下的所有prototype标签
                    List<Element> property = beanElt.elements("property");
                    //遍历所有的属性标签
                    property.forEach(prototypeElt -> {

                        try {
                            String propertyName = prototypeElt.attributeValue("name");
                            logger.info("属性名：" + propertyName);
                            //获取属性类型
                            Field field = aClass.getDeclaredField(propertyName);
                            //获取set方法名
                            String setMethodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
                            System.out.println(setMethodName);

                            Method method = aClass.getDeclaredMethod(setMethodName, field.getType());

                            String value = prototypeElt.attributeValue("value");
                            String ref =   prototypeElt.attributeValue("ref");
                            Object actualValue;
                            if(value!=null && !value.equals("")){
                                //调用set方法，给属性赋值
                                String simpleName = field.getType().getSimpleName();
                                switch(simpleName){
                                    case "String":
                                        actualValue=value;
                                        break;
                                    case "int":
                                        actualValue=Integer.parseInt(value);
                                        break;
                                    case "long":
                                        actualValue=Long.parseLong(value);
                                        break;
                                    case "boolean":
                                        actualValue=Boolean.parseBoolean(value);
                                        break;
                                    case "double":
                                        actualValue=Double.parseDouble(value);
                                        break;

                                        case "float":
                                        actualValue=Float.parseFloat(value);

                                        break;
                                    case "short":
                                        actualValue=Short.parseShort(value);
                                        break;
                                    case "byte":
                                        actualValue=Byte.parseByte(value);
                                        break;

                                    default:
                                        throw new RuntimeException("不支持的类型");

                                }
                                method.invoke(singletonObeject.get(id),actualValue);
                            }else if(ref!=null && !ref.equals("")){
                                //调用set方法，给属性赋值
                                method.invoke(singletonObeject.get(id),singletonObeject.get(ref));
                            }

                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }


                    });

                }catch(Exception e){

                    }
            });
        }catch(Exception e){

            e.printStackTrace();
        }
    }
    @Override
    public Object getBean(String name) {
        return singletonObeject.get(name);
    }
}
